﻿using System;
using System.Collections.Generic;
using System.Linq;
using TPOJ.IDAL;
using TPOJ.Model;
using System.Data;

namespace TPOJ.LINQDAL
{
    public class SolutionDAO : ISolutionDAO
    {

        #region ISolutionDAO Members

        public TPOJ.Model.Solution GetSolution(int id)
        {
            Solution result;
            using (var entities = new TPOJEntities())
            {
                var query = from solution in entities.Solutions
                            where solution.UniqueID == id
                            select solution;
                result = query.First();
            }
            return result;
        }

        public Solution AddSolution(int problemId, string language, string code, int userId, int? contestId, DateTime submitTime)
        {
            Solution solution;
            using (var entities = new TPOJEntities())
            {
                solution = entities.Solutions.CreateObject();

                solution.Language = language;
                solution.Code = code;
                solution.CodeLength = code.Length;
                solution.AccountID = userId;
                solution.DateTime = submitTime;

                entities.Solutions.AddObject(solution);

                var queryProblem = from p in entities.Problems
                                   where p.UniqueID == problemId
                                   select p;
                solution.Problem = queryProblem.First();

                solution.Problem.Summit++;

                if (contestId != null)
                {
                    var queryContest = from c in entities.Contests
                                       where c.UniqueID == contestId
                                       select c;
                    solution.Contest = queryContest.First();
                }

                try
                {
                    entities.SaveChanges();
                }
                catch (OptimisticConcurrencyException)
                {
                    entities.Refresh(System.Data.Objects.RefreshMode.ClientWins, solution);
                    entities.SaveChanges();
                }
            }
            return solution;
        }

        public void EditSolution(Solution solution,bool isAC)
        {
            using (var entities = new TPOJEntities())
            {
                var query = entities.Solutions.Include("Problem").Where(s => s.UniqueID == solution.UniqueID);
                Solution sol = query.First();

                sol.Result = solution.Result;
                sol.Time = solution.Time;
                sol.Memory = solution.Memory;
                sol.ErrorMessage = solution.ErrorMessage;

                if (isAC)
                {
                    sol.Problem.Solved++;
                }

                entities.SaveChanges();
            }
        }

        public IList<TPOJ.Model.Solution> GetAllSolutions()
        {
            IList<Solution> result = new List<Solution>();

            using (var entities = new TPOJEntities())
            {
                var query = entities.Solutions.Include("Problem");
                foreach (var s in query)
                {
                    result.Add(s);
                }
            }
            return result;
        }

        public IList<Solution> GetContestSolutions(int contestId)
        {
            IList<Solution> result = new List<Solution>();

            using (var entities = new TPOJEntities())
            {
                var solutions = entities.Solutions.Include("Problem").Include("Contest");
                var query = from s in solutions
                            where s.Contest != null && s.Contest.UniqueID == contestId
                            select s;
                foreach (var s in query)
                {
                    result.Add(s);
                }
            }
            return result;
        }

        public IList<Solution> GetProblemSolutions(int problemId)
        {
            IList<Solution> result = new List<Solution>();

            using (var entities = new TPOJEntities())
            {
                var solutions = entities.Solutions.Include("Problem");
                var query = from s in solutions
                            where s.Problem.UniqueID == problemId
                            select s;
                foreach (var s in query)
                {
                    result.Add(s);
                }
            }
            return result;
        }

        public IList<int> GetSolvedProblemIdsByUser(int userId)
        {
            IList<int> result = new List<int>();

            using (var entities = new TPOJEntities())
            {
                var query = from s in entities.Solutions.Include("Problem")
                            where s.AccountID == userId && s.Result == 13//magic number here for AC
                            orderby s.Problem.UniqueID
                            select s.Problem.UniqueID;
                foreach (var i in query.Distinct())
                {
                    result.Add(i);
                } 
            }
            return result;
        }

        public IList<int> GetTriedNotACedProblemIdsByUser(int userId)
        {
            IList<int> result = new List<int>();

            using (var entities = new TPOJEntities())
            {
                var query = from s in entities.Solutions.Include("Problem")
                            where s.AccountID == userId
                            orderby s.Problem.UniqueID
                            select s.Problem.UniqueID;
                foreach (var i in query.Distinct().Except(GetSolvedProblemIdsByUser(userId)))
                {
                    result.Add(i);
                }
            }
            return result;
        }

        #endregion


        public IList<int> GetSolvedProblemIdsByUserInContest(int userId, int contestId)
        {
            IList<int> result = new List<int>();

            using (var entities = new TPOJEntities())
            {
                var query = from s in entities.Solutions.Include("Problem").Include("Contest")
                            where s.Contest.UniqueID == contestId && s.AccountID == userId && s.Result == 13//magic number here for AC
                            orderby s.Problem.UniqueID
                            select s.Problem.UniqueID;
                foreach (var i in query.Distinct())
                {
                    result.Add(i);
                }
            }
            return result;
        }

        public IList<int> GetTriedNotACedProblemIdsByUserInContest(int userId, int contestId)
        {
            IList<int> result = new List<int>();

            using (var entities = new TPOJEntities())
            {
                var query = from s in entities.Solutions.Include("Problem").Include("Contest")
                            where s.AccountID == userId && s.Contest.UniqueID == contestId
                            orderby s.Problem.UniqueID
                            select s.Problem.UniqueID;
                foreach (var i in query.Distinct().Except(GetSolvedProblemIdsByUserInContest(userId, contestId)))
                {
                    result.Add(i);
                }
            }
            return result;
        }
    }
}
